package com.jiatuxueyuan.the4.remoteio;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;

public class Zlan6842ModbusTcp {

    private short tx = 0x0000;

    private short protocol = 0x0000;

    private short length;

    private byte slaveAddr = 0x01;

    private byte funcCode = 0x05;

    private int doIndex;

    private boolean openOrClose;

    private final static int[] DO_INDEX_ARRAY = {0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017};

    public Zlan6842ModbusTcp(byte slaveAddr, byte funcCode, int doIndex, boolean openOrClose) {
        if(doIndex > 8 || doIndex < 1) {
            throw new IllegalArgumentException("DO端口序号错误，取值范围1-8");
        }
        this.tx = 0x0000;
        this.protocol = 0x0000;
        this.slaveAddr = slaveAddr;
        this.funcCode = funcCode;
        this.doIndex = doIndex;
        this.openOrClose = openOrClose;
    }


    ByteBuf createPDU() {
        ByteBuf buf = Unpooled.buffer(12);
        buf.writeShort(this.tx); // Modbus TCP报文事务标记，我们用不到这个，所以就传0
        buf.writeShort(this.protocol);// 协议标识符，2个字节，也用不上，此处传0x0000
        buf.writeShort(6);  //Modbus TCP报文中的长度字段，占2个字节，指的是随后的字节总数，看下面的代码，2个writeByte、2个writeShort，一共是 1 + 1 + 2 + 2 = 6个字节
        buf.writeByte(this.slaveAddr); //从站地址，1个字节
        buf.writeByte(this.funcCode); //功能码，1个字节
        buf.writeShort(DO_INDEX_ARRAY[doIndex]);
        if(this.openOrClose) { //打开DO口，输出高电平，如果这个DO口上接了电磁阀、继电器之类的，那么电磁阀和继电器就会导通
            buf.writeShort(0xFF00);
        } else {
            buf.writeShort(0x0000);
        }
        return buf;
    }


    public static void main(String[] args) {
        Zlan6842ModbusTcp tcp = new Zlan6842ModbusTcp((byte)0x01, (byte)0x05, 1, true);
        ByteBuf msg = tcp.createPDU();
        System.out.println(ByteBufUtil.hexDump(msg));
    }
}
